package blog.router.impl;

import blog.model.BlogContent;
import blog.model.PageData;
import blog.router.LoadRouter;
import blog.util.MySQLUtil;
import blog.util.RsUtil;
import blog.util.StringUtils;
import io.vertx.core.Future;
import io.vertx.core.json.JsonArray;
import io.vertx.ext.web.Router;
import io.vertx.ext.web.RoutingContext;
import io.vertx.sqlclient.Row;
import io.vertx.sqlclient.RowSet;
import io.vertx.sqlclient.Tuple;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.time.LocalDateTime;
import java.util.LinkedList;
import java.util.List;

/**
 * 博文相关接口
 */
public class BlogContentRouter implements LoadRouter {

  private final static Logger logger = LoggerFactory.getLogger(BlogContentRouter.class);
  private final Router router;

  private final String contextPath;

  public BlogContentRouter(Router router, String contextPath) {
    logger.info("blog router enable");
    this.router = router;
    this.contextPath = contextPath;
  }

  public BlogContentRouter add() {
    router.post(contextPath + "/content").handler(ctx -> {
      String insert = MySQLUtil.insert("blog_content", "blog_title", "blog_describe", "content", "create_time");
      ctx.request().body(rb -> {
        BlogContent content = rb.result().toJsonObject().mapTo(BlogContent.class);
        if (!checkParam(content, ctx)) {
          return;
        }
        logger.info("add blog insert sql: {}", insert);
        Future<RowSet<Row>> execute = MySQLUtil.run(ctx.vertx()).preparedQuery(insert)
          .execute(Tuple.of(content.getBlogTitle(), content.getBlogDescribe(), content.getContent(), LocalDateTime.now()));
        execute.onSuccess(r -> ctx.json(RsUtil.success("发布成功")));
        execute.onFailure(ctx::fail);
      });
    }).failureHandler(ctx -> {
      logger.error("add blog error:{}", ctx.failure().getMessage());
      ctx.json(RsUtil.error(500, "添加失败:" + ctx.failure().getMessage()));
    });
    return this;
  }

  public BlogContentRouter del() {
    router.delete(contextPath + "/content").handler(ctx -> ctx.request().body(rb -> {
      JsonArray objects = rb.result().toJsonArray();
      List<Tuple> deleteIds = new LinkedList<>();
      for (Object id : objects) {
        deleteIds.add(Tuple.of(id));
      }
      String deleteSQL = MySQLUtil.delete("blog_content", "id = ?");
      logger.info("delete blog sql:{}", deleteSQL);
      Future<RowSet<Row>> rowSetFuture = MySQLUtil.run(ctx.vertx()).preparedQuery(deleteSQL).executeBatch(deleteIds);
      rowSetFuture.onSuccess(r -> ctx.json(RsUtil.success("删除成功")));
      rowSetFuture.onFailure(ctx::fail);
    })).failureHandler(ctx -> {
      logger.error("delete blog error:{}", ctx.failure().getMessage());
      ctx.json(RsUtil.error(500, "删除失败:" + ctx.failure().getMessage()));
    });
    return this;
  }

  public BlogContentRouter set() {
    router.put(contextPath + "/content").handler(ctx -> ctx.request().body(rb -> {
      BlogContent content = rb.result().toJsonObject().mapTo(BlogContent.class);
      if (content.getId() == null) {
        throw new RuntimeException("缺少更新id");
      }
      String updateSQL = MySQLUtil.updateById("blog_content", content.getId(), "blog_title", "blog_describe", "content");
      logger.info("update blog sql:{}", updateSQL);
      Future<RowSet<Row>> execute = MySQLUtil.run(ctx.vertx()).preparedQuery(updateSQL).execute(Tuple.of(content.getBlogTitle(), content.getBlogDescribe(), content.getContent()));
      execute.onSuccess(r -> ctx.json(RsUtil.success("修改成功")));
      execute.onFailure(ctx::fail);
    })).failureHandler(ctx -> {
      logger.error("update blog error:{}", ctx.failure().getMessage());
      ctx.json(RsUtil.error(500, "修改失败:" + ctx.failure().getMessage()));
    });
    return this;
  }

  public BlogContentRouter list() {
    router.get(contextPath + "/content").handler(ctx -> {
      long startTime = System.currentTimeMillis();
      int pageNum = Integer.parseInt(ctx.request().getParam("pageNum", "1"));
      int pageSize = Integer.parseInt(ctx.request().getParam("pageSize", "10"));
      String keyworkd = ctx.request().getParam("keyword");
      String whereStr = "";
      boolean isKeywordModel = false;
      if (!StringUtils.isEmpty(keyworkd)) {
        whereStr = " WHERE blog_title like '%" + keyworkd + "%' OR blog_describe like '%" + keyworkd + "%'";
        isKeywordModel = true;
      }
      String finalWhereStr = whereStr;
      boolean finalIsKeywordModel = isKeywordModel;
      MySQLUtil.run(ctx.vertx()).query("select count(*) from blog_content" + whereStr).execute(er -> {
        if (er.succeeded()) {
          Integer count = er.result().iterator().next().getInteger(0);
          String select = MySQLUtil
            .select("blog_content", "id", "blog_title", "blog_describe", "create_time") + finalWhereStr;
          logger.info("list blog content sql:{}", select);
          MySQLUtil.run(ctx.vertx()).query(select + " ORDER BY id DESC LIMIT " + pageSize + " OFFSET " + (pageNum - 1) * pageSize)
            .execute(ar -> {
              List<BlogContent> list = new LinkedList<>();
              if (ar.result() != null) {
                for (Row row : ar.result()) {
                  BlogContent content = new BlogContent();
                  content.setId(row.getInteger("id"));
                  content.setBlogTitle(row.getString("blog_title"));
                  content.setBlogDescribe(row.getString("blog_describe"));
                  content.setCreateTime(row.getLocalDateTime("create_time"));
                  list.add(content);
                }
              }
              long endTime = System.currentTimeMillis();
              if (finalIsKeywordModel) {
                list.forEach(item -> {
                  item.setBlogTitle(StringUtils.highlight(item.getBlogTitle(), keyworkd));
                  item.setBlogDescribe(StringUtils.highlight(item.getBlogDescribe(), keyworkd));
                });
              }
              PageData<BlogContent> pageData = PageData.builder(BlogContent.class).currentPageNum(pageNum).currentPageSize(pageSize).list(list).takeTime(endTime - startTime).total(count).build();
              ctx.json(RsUtil.success("查询成功", pageData));
            });
        } else {
          ctx.json(RsUtil.error(500, ctx.failure().getMessage()));
        }
      });

    }).failureHandler(ctx -> ctx.json(RsUtil.error(500, "查询失败:" + ctx.failure().getMessage())));
    return this;
  }

  public void detail() {
    router.get(contextPath + "/content/detail/:id").handler(ctx -> {
      String id = ctx.request().getParam("id");
      String select = MySQLUtil.select("blog_content", "blog_title", "content", "create_time");
      Future<RowSet<Row>> execute = MySQLUtil.run(ctx.vertx()).preparedQuery(select + " WHERE id = ?").execute(Tuple.of(id));
      execute.onSuccess(er -> {
        if (er.iterator().hasNext()) {
          Row blog = er.iterator().next();
          BlogContent blogContent = new BlogContent();
          blogContent.setContent(blog.getString("blog_title"));
          blogContent.setContent(blog.getString("content"));
          blogContent.setCreateTime(blog.getLocalDateTime("create_time"));
          ctx.json(RsUtil.success("查询成功", blogContent));
        } else {
          ctx.json(RsUtil.error(204, "该id不存在相应内容，请确认请求参数"));
        }
      });
      execute.onFailure(err -> ctx.json(RsUtil.error(500, err.getMessage())));
    }).failureHandler(err -> err.json(RsUtil.error(500, err.failure().getMessage())));
  }

  @Override
  public void loadAll() {
    this.add().del().set().list().detail();
  }

  private boolean checkParam(BlogContent content, RoutingContext ctx) {
    boolean result = true;
    if (content == null) {
      result = false;
      ctx.fail(406, new RuntimeException("无效的参数"));
    } else if (StringUtils.isEmpty(content.getBlogTitle())) {
      result = false;
      ctx.fail(406, new RuntimeException("请输入博文标题"));
    } else if (StringUtils.isEmpty(content.getBlogDescribe())) {
      result = false;
      ctx.fail(406, new RuntimeException("请输入博文描述"));
    } else if (StringUtils.isEmpty(content.getContent())) {
      result = false;
      ctx.fail(406, new RuntimeException("请输入博文正文"));
    }
    return result;
  }
}
